/**
 * CatsDogsMain.java
 */

package rainingcatsdogs;

import java.io.IOException;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextField;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * The CatsDogsMain class that handles commands, main menu and running of the
 * game.
 */
public class CatsDogsMain extends MIDlet implements CommandListener {

	/**
	 * Allows the game and menu screens to be displayed through the MIDLet.
	 */
	public Display display;

	/**
	 * The list of items available on the main menu.
	 */
	private List list;

	/**
	 * The list that displays the options menu.
	 */
	private List optionsScreen;

	/**
	 * The list that displays the difficulty settings.
	 */
	private List difficultyScreen;

	/**
	 * The list that displays the music settings.
	 */
	private List musicScreen;

	/**
	 * The list that displays the sound effects settings.
	 */
	private List soundEffectsScreen;

	/**
	 * The variable which stores the value of the difficulty setting.
	 */
	private int difficulty = 0;

	/**
	 * The variable for turning music on or off.
	 */
	private boolean music = true;

	/**
	 * The variable for turning sound effects on or off.
	 */
	private boolean soundEffects = true;

	/**
	 * The command which exits the current screen.
	 */
	private Command exit;

	/**
	 * The command which advances to the next option.
	 */
	private Command next;

	/**
	 * The command which takes the player one screen back.
	 */
	private Command back;

	/**
	 * The command which is designed to launch the game.
	 */
	private Command launchGame;

	/**
	 * The alert that allows the credits screen to be displayed.
	 */
	private Alert creditScreen;

	/**
	 * The introductory splash screen form that is displayed when the game is
	 * initially run.
	 */
	private Form welcome;

	/**
	 * The game over screen.
	 */

	private Form gameOver;

	/**
	 * The upgrade selection list
	 */
	private List upgradeForm;

	/**
	 * The command which allows the game to be played again.
	 */
	private Command playAgain;

	/**
	 * The command which returns the player to the main menu.
	 */

	private Command mainMenu;

	/**
	 * The class which handles the graphics of the game and how it is run.
	 */
	private CatsDogsCanvas gameCanvas;

	/**
	 * The welcome image that appears on the splash screen.
	 */
	private Image img;

	/**
	 * The image that represents starting a new game on the main menu.
	 */
	private Image start;

	/**
	 * The image that represents the high scores on the main menu.
	 */
	private Image high;

	/**
	 * The image that represents the options page on the main menu.
	 */
	private Image option;

	/**
	 * The image that represents the help screen on the main menu.
	 */
	private Image help;

	/**
	 * The image that represents the credits screen on the main menu.
	 */
	private Image credit;

	/**
	 * The image that represents quitting the game on the main menu.
	 */
	private Image quit;

	/**
	 * The image that represents the turret upgrade on the upgrade menu.
	 */
	private Image turretUpgrade;

	/**
	 * The image that represents the bullet upgrade on the upgrade menu.
	 */
	private Image bulletUpgrade;

	/**
	 * The image that represents the life upgrade on the upgrade menu.
	 */
	private Image lifeUpgrade;

	/**
	 * The image that represents the bomb upgrade on the upgrade menu.
	 */
	private Image bombUpgrade;

	/**
	 * The Highscore object that stores high scores.
	 */
	private Highscore highScore;

	/**
	 * The form that allows a name for the new high score to be inputed.
	 */
	private Form newScoreScreen;

	/**
	 * The Alert that displays high scores..
	 */
	private Alert highScoreScreen;

	/**
	 * Command to accept a name from the player for a new high score.
	 */
	private Command acceptName;

	/**
	 * Text field to accept a name from the player for a new high score.
	 */
	private TextField newName;

	/**
	 * The music to play when navigating through menus
	 */
	private Player menuMusic = null;

	/**
	 * The list of strings that are added to the main menu. They declare where
	 * each item in the main menu is supposed to lead.
	 */
	String[] stringOptions = { "Start Game", "High Scores", "Options", "Help",
			"Credits", "Quit" };

	/**
	 * The CatsDogsMain public constructor which handles the creation of the
	 * main menu.
	 */
	public CatsDogsMain() {
		welcome = new Form("Cats Dogs");
		this.highScore = new Highscore();

		try {
			img = Image.createImage("/welcome.png");
			start = Image.createImage("/start.png");
			high = Image.createImage("/high.png");
			option = Image.createImage("/option.png");
			help = Image.createImage("/help.png");
			credit = Image.createImage("/credit.png");
			quit = Image.createImage("/quit.png");

		} catch (Exception e) {

		}
		next = new Command("Select", Command.SCREEN, 0);
		exit = new Command("Exit", Command.EXIT, 0);
		back = new Command("Back", Command.BACK, 0);
		launchGame = new Command("Launch", Command.OK, 0);

		// TO DO:
		playAgain = new Command("Play Again", Command.OK, 0);
		mainMenu = new Command("Main Menu", Command.BACK, 0);
		gameOver = new Form("Game Over");
		// we can add image to this
		gameOver.append("Game Over !!!!!");
		gameOver.addCommand(playAgain);
		gameOver.addCommand(mainMenu);
		gameOver.setCommandListener(this);

		// Creates the screen that accepts a name for a new high score
		this.acceptName = new Command("Accept", Command.OK, 0);
		this.newName = new TextField("Enter your Name: ", "", 3, TextField.ANY);
		this.newScoreScreen = new Form("New High Score!");
		this.newScoreScreen.append(this.newName);
		this.newScoreScreen
				.append("Congratulations! You have earned a place in our pantheon of top dispatchers of animal terrorism. Enter your name below so our 500 blind sculptors can carve your name into the moon.");
		this.newScoreScreen.addCommand(this.acceptName);
		this.newScoreScreen.setCommandListener(this);

		// create image array for List
		Image[] imageOptions = { start, high, option, help, credit, quit };
		String[] stringOptions = { "Start Game", "High Scores", "Options",
				"Help", "Credits", "Quit" };
		list = new List("Main Menu", List.IMPLICIT, stringOptions, imageOptions);
		list.addCommand(next);
		list.addCommand(exit);
		list.setCommandListener(this);

		// Creates the screen for the high scores.
		this.highScoreScreen = new Alert("High Scores",
				this.highScore.toString(), null, AlertType.INFO);
		this.highScoreScreen.addCommand(this.mainMenu);
		this.highScoreScreen.setTimeout(Alert.FOREVER);
		this.highScoreScreen.setCommandListener(this);

		// create options screen list
		Image[] optionsImageOptions = { null, null, null };
		String[] optionsStringOptions = { "Difficulty", "Music",
				"Sound Effects" };
		optionsScreen = new List("Options", List.IMPLICIT,
				optionsStringOptions, optionsImageOptions);
		optionsScreen.addCommand(next);
		optionsScreen.addCommand(back);
		optionsScreen.setCommandListener(this);

		// create difficulty screen list
		Image[] difficultyImageOptions = { null, null, null };
		String[] difficultyStringOptions = { "Easy", "Medium", "Hard" };
		difficultyScreen = new List("Difficulty", List.IMPLICIT,
				difficultyStringOptions, difficultyImageOptions);
		difficultyScreen.addCommand(next);
		difficultyScreen.addCommand(back);
		difficultyScreen.setCommandListener(this);

		// create music screen list
		Image[] musicImageOptions = { null, null };
		String[] musicStringOptions = { "On", "Off" };
		musicScreen = new List("Music", List.IMPLICIT, musicStringOptions,
				musicImageOptions);
		musicScreen.addCommand(next);
		musicScreen.addCommand(back);
		musicScreen.setCommandListener(this);

		// create sound effects screen list
		Image[] soundEffectsImageOptions = { null, null };
		String[] soundEffectsStringOptions = { "On", "Off" };
		soundEffectsScreen = new List("Sound Effects", List.IMPLICIT,
				soundEffectsStringOptions, soundEffectsImageOptions);
		soundEffectsScreen.addCommand(next);
		soundEffectsScreen.addCommand(back);
		soundEffectsScreen.setCommandListener(this);

	}

	/**
	 * Finishes the game and displays a screen when all lives have been lost.
	 */
	public void gameOver() {
		if (this.gameCanvas.getCurrentScore() > this.highScore.getLowestScore()) {
			this.display.setCurrent(this.newScoreScreen);
		} else {
			this.getDisplay().setCurrent(this.gameOver);
		}
	}

	/**
	 * The method which starts the application and launches the game.
	 * 
	 * @see javax.microedition.midlet.MIDlet#startApp()
	 */
	protected void startApp() throws MIDletStateChangeException {
		if (this.gameCanvas != null) {
			// In case we are resuming from a paused state
			this.gameCanvas.prefetchResources();
		} else {
			welcome.append(img);
			welcome.addCommand(launchGame);
			welcome.setCommandListener(this);
			try {
				this.menuMusic = Manager.createPlayer(getClass()
						.getResourceAsStream("/movinout.wav"), "audio/x-wav");
				this.menuMusic.setLoopCount(-1);
				if (this.menuMusic.getState() != Player.STARTED && this.music) {
					this.menuMusic.start();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (MediaException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			display = Display.getDisplay(this);
			display.setCurrent(welcome);

		}
	}

	/**
	 * The method which destroys the application and finishes the game.
	 * 
	 * @see javax.microedition.midlet.MIDlet#destroyApp(boolean)
	 */
	protected void destroyApp(boolean arg0) {
		notifyDestroyed();

	}

	/**
	 * The method which pauses the application and the game.
	 * 
	 * @see javax.microedition.midlet.MIDlet#pauseApp()
	 */
	protected void pauseApp() {
		if (this.gameCanvas.isRunning()) {
			this.gameCanvas.pause();
			this.gameCanvas.releaseResources();
		}
	}

	/**
	 * Show the help alert
	 * 
	 * @param displayable
	 */
	public void helpAlert(Displayable displayable) {
		Alert helpScreen = new Alert(
				"Help",
				"LEFT BUTTON or BUTTON 4: Move the player left"
						+ "\n"
						+ "RIGHT BUTTON or BUTTON 6: Move the player right"
						+ "\n"
						+ "MIDDLE BUTTON or BUTTON 5: Use your primary weapon"
						+ "\n"
						+ "BUTTON 1: Use your secondary weapon"
						+ "\n\n"
						+ "The objective of the game is to shoot falling cats and dogs before they hit the ground or the player."
						+ "If an enemy reaches the ground or the player, the player will lose hit points."
						+ "Lose 100 hit points and the player will lose a life."
						+ "The game is over when all lives are lost."
						+ "Points can be gained by killing cats and dogs."
						+ "At the end of each level, one of three upgrades can be bought with the points accumulated.",
				null, AlertType.INFO);
		helpScreen.setTimeout(Alert.FOREVER);
		display.setCurrent(helpScreen, displayable);
	}

	/**
	 * The method which controls the functions of the main menu items.
	 * 
	 * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command,
	 *      javax.microedition.lcdui.Displayable)
	 */
	public void commandAction(Command c, Displayable displayable) {

		if (displayable == list) {

			int index = list.getSelectedIndex();
			switch (index) {
			case 0:
				
				gameCanvas = new CatsDogsCanvas(this, this.difficulty,
						this.music, this.soundEffects);
				
				if(!this.gameCanvas.isLoaded()) {
					Alert error = new Alert("Error", "Unable to load vital images. Cannot load game", null, AlertType.ERROR);
					this.getDisplay().setCurrent(error, this.getList());
				} else {
					try {
						this.menuMusic.stop();
					} catch (MediaException e) {
						// Ignore music failure
					}
					
					gameCanvas.start();
					display.setCurrent(gameCanvas);
				}
				break;

			case 1:
				this.display.setCurrent(this.highScoreScreen);
				break;

			case 2:
				display.setCurrent(this.getOptionsScreen());
				break;

			case 3:
				this.helpAlert(this.list);
				break;

			case 4:
				creditScreen = new Alert("Credits", "Created by: " + "\n"
						+ "Andrew Gee" + "\n" + "David Bainbridge" + "\n"
						+ "Joseph Luo" + "\n" + "Karesh Arunakirinathan" + "\n"
						+ "Robert Fawn", null, AlertType.INFO);
				creditScreen.setTimeout(Alert.FOREVER);
				display.setCurrent(creditScreen, list);
				break;

			case 5:
				destroyApp(true);
				break;
			}

		} else if (display.getCurrent() == optionsScreen) {
			if (c == back) {
				display.setCurrent(list);
			} else {
				int optionsIndex = optionsScreen.getSelectedIndex();
				switch (optionsIndex) {
				case 0:
					display.setCurrent(this.getDifficultyScreen());
					break;
				case 1:
					display.setCurrent(this.getMusicScreen());
					break;
				case 2:
					display.setCurrent(this.getSoundEffectsScreen());
					break;
				}
			}
		} else if (display.getCurrent() == difficultyScreen) {
			if (c == back) {
				display.setCurrent(optionsScreen);
			} else {
				int difficultyIndex = difficultyScreen.getSelectedIndex();
				this.difficulty = difficultyIndex;
				display.setCurrent(getList());
			}
		} else if (display.getCurrent() == musicScreen) {
			if (c == back) {
				display.setCurrent(optionsScreen);
			} else {
				int musicIndex = musicScreen.getSelectedIndex();
				this.music = musicIndex == 0;

				try {
					if(this.music) {
						if(this.menuMusic.getState() != Player.STARTED) {
								this.menuMusic.start();
						}
					} else {
						this.menuMusic.stop();
					}
				} catch (MediaException e) {
					// Ignore failing of music.
				}
				
				display.setCurrent(getList());
			}
		} else if (display.getCurrent() == soundEffectsScreen) {
			if (c == back) {
				display.setCurrent(optionsScreen);
			} else {
				int soundEffectsIndex = soundEffectsScreen.getSelectedIndex();
				this.soundEffects = soundEffectsIndex == 0;
				display.setCurrent(getList());
			}
		} else if (this.display.getCurrent() == this.newScoreScreen) {
			this.highScore.replaceRecord(this.newName.getString(),
					this.gameCanvas.getCurrentScore());
			this.highScoreScreen.setString(this.highScore.toString());
			this.display.setCurrent(this.highScoreScreen);
		} else if (this.display.getCurrent() == this.upgradeForm) {
			switch (this.upgradeForm.getSelectedIndex()) {
			case 0:
				this.gameCanvas.upgradeTurret();
				break;
			case 1:
				this.gameCanvas.upgradeBullets();
				break;
			case 2:
				this.gameCanvas.addLife();
				break;
			case 3:
				this.gameCanvas.addBomb();
				break;
			}
			this.display.setCurrent(this.gameCanvas);
			this.gameCanvas.reset();
			this.gameCanvas.resume();
		}

		if (c == mainMenu) {
			display.setCurrent(list);
		}

		if (c == playAgain) {
			gameCanvas = new CatsDogsCanvas(this, this.difficulty, this.music,
					this.soundEffects);
			gameCanvas.start();
			display.setCurrent(gameCanvas);
		}

		if (c == exit) {
			destroyApp(true);
		}

		if (c == launchGame) {
			display.setCurrent(list);
		}
	}

	/**
	 * Gets the display for the application to display items on the screen
	 * @return the display for the application so that it can be seen
	 */
	public Display getDisplay() {
		return display;
	}

	/**
	 * The setter method which sets the display for the application in order for
	 * it to be seen on the screen.
	 * 
	 * @param display
	 */
	public void setDisplay(Display display) {
		this.display = display;
	}

	/**
	 * Return the list of menus
	 * 
	 * @return list list of menus
	 */
	public List getList() {
		return list;
	}

	/**
	 * Return the game over form
	 * 
	 * @return list game over form
	 */

	public Form getGameover() {
		return gameOver;
	}

	/**
	 * The method that sets the options screen list.
	 * 
	 * @param optionsScreen
	 */
	public void setOptionsScreen(List optionsScreen) {
		this.optionsScreen = optionsScreen;
	}

	/**
	 * Gets the option screen form
	 * 
	 * @return the options screen list
	 */
	public List getOptionsScreen() {
		return optionsScreen;
	}

	/**
	 * Gets the difficulty screen to display to the user
	 * @return the difficulty screen list
	 */
	public List getDifficultyScreen() {
		return difficultyScreen;
	}

	/**
	 * The method that sets the difficulty screen list.
	 * 
	 * @param difficultyScreen
	 */
	public void setDifficultyScreen(List difficultyScreen) {
		this.difficultyScreen = difficultyScreen;
	}

	/**
	 * Returns the music screen form.
	 * @return the music screen list
	 */
	public List getMusicScreen() {
		return musicScreen;
	}

	/**
	 * The method that sets the music screen list.
	 * 
	 * @param musicScreen
	 */
	public void setMusicScreen(List musicScreen) {
		this.musicScreen = musicScreen;
	}

	/**
	 * Gets the sound effects screen form allowing the user to toggle the playing of sound affects
	 * 
	 * @return the sound effects screen list
	 */
	public List getSoundEffectsScreen() {
		return soundEffectsScreen;
	}

	/**
	 * The method that sets the sound effects screen list.
	 * 
	 * @param soundEffectsScreen
	 */
	public void setSoundEffectsScreen(List soundEffectsScreen) {
		this.soundEffectsScreen = soundEffectsScreen;
	}

	/**
	 * Show the screen to upgrade certain things for the next level
	 */
	public void upgradeScreen() {
		try {
			turretUpgrade = Image.createImage("/turretupgrade.png");
			bulletUpgrade = Image.createImage("/bulletupgrade.png");
			lifeUpgrade = Image.createImage("/lifeupgrade.png");
			bombUpgrade = Image.createImage("/bombupgrade.png");
		} catch (Exception e) {

		}
		String[] upgradeStringOptions = { "Faster Turret", "Faster Bullets",
				"Extra Life", "Extra Bomb" };
		Image[] upgradeImageOptions = { turretUpgrade, bulletUpgrade,
				lifeUpgrade, bombUpgrade };
		this.upgradeForm = new List("Choose 1 upgrade", List.IMPLICIT,
				upgradeStringOptions, upgradeImageOptions);
		this.upgradeForm.addCommand(next);
		this.upgradeForm.setCommandListener(this);
		this.display.setCurrent(this.upgradeForm);
	}
	
	/**
	 * Return to the main menu from the game
	 */
	public void returnMainMenu() {
		if (this.menuMusic.getState() != Player.STARTED && this.music) {
			try {
				this.menuMusic.start();
			} catch (MediaException e) {
				// Ignore on error - Just go to the main menu without music
			}
		}
		this.display.setCurrent(this.getList());
	}
}
